﻿using System;
using System.Windows;
using System.Windows.Controls;
using SRS.Encryption;

namespace SRS
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        #region Event
        private void buttonEncrypt_Click(object sender, RoutedEventArgs e)
        {
            if (ValidateCommonForm() && ValidateEncryptForm())
            {
                Encrypt();
            }
        }

        private void buttonDecrypt_Click(object sender, RoutedEventArgs e)
        {
            if (ValidateCommonForm() && ValidateDecryptForm())
            {
                Decrypt();
            }
        }

        private void comboBoxEncryptionMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (comboBoxEncryptionMode.SelectedIndex > 1 && textBoxKey.Text.Length > 0)
            {
                // CFB or OFB are selected
                labelUnitLength.IsEnabled = comboBoxUnitLength.IsEnabled = true;

                // Generate items for comboBoxUnitLength
                GenerateItemsComboBoxUnitLength();
            }
            else
            {
                // ECB or CBC are selected
                if (labelUnitLength != null && comboBoxUnitLength != null)
                {
                    labelUnitLength.IsEnabled = comboBoxUnitLength.IsEnabled = false;
                }
            }
        }

        private void GenerateItemsComboBoxUnitLength()
        {
            int length = textBoxKey.Text.Length;

            // Evaluate Length
            if (length < 8)
            {
                length = 8;
            }

            // Clear
            comboBoxUnitLength.Items.Clear();

            // Generate
            for (int i = 0; i < length; ++i)
            {
                comboBoxUnitLength.Items.Add(i + 1);
            }

            // Set selected index
            comboBoxUnitLength.SelectedIndex = 0;
        }

        private void textBoxKey_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (comboBoxEncryptionMode.SelectedIndex > 1)
            {
                comboBoxUnitLength.IsEnabled = true;
            }

            if (textBoxKey.Text.Length < 1)
            {
                comboBoxUnitLength.IsEnabled = false;
            }

            if (comboBoxUnitLength.IsEnabled)
            {
                GenerateItemsComboBoxUnitLength();
            }
        }

        private void menuItemExit_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void menuItemAbout_Click(object sender, RoutedEventArgs e)
        {
            String str = "Develop by : \n\nSandy Socrates - 13508044\nIsmail Sunni - 13508064\nRezan Achmad - 13508104";
            MessageBox.Show(str, "About");
        }

        #endregion

        #region Encryption

        #region Encrypt

        private void Encrypt()
        {
            byte[] body;
            SRSEncryption srs = GetEncryptionAlgorithm(comboBoxEncryptionMode.SelectedIndex);

            byte[] keyBytes = GetKey();
            byte[] plainBytes = Helper.StringToArrayByte(editorPlainText.TextBox.Text);
            int unitLength = comboBoxUnitLength.SelectedIndex + 1;

            // Header
            byte[] header = EncryptHeader(keyBytes, plainBytes.Length, unitLength, comboBoxEncryptionMode.SelectedIndex);

            // Body
            body = srs.Encrypt(keyBytes, plainBytes, unitLength);

            editorCipherText.TextBox.Text = Helper.ArrayByteToString(Helper.Concat(header, body));
        }

        private byte[] EncryptHeader(byte[] keyBytes, int plainLength, int unitLength, int mode)
        {
            int keyLength = keyBytes.Length;
            byte[] header = new byte[keyLength];

            // Mode
            header[0] = (byte)mode;

            // Block Length
            header[1] = (byte)keyLength;

            // Unit Length
            header[2] = (byte)unitLength;

            // Padding
            if (mode == 0 || mode == 1)
            {
                header[3] = (byte)((keyLength - (plainLength % keyLength)) % keyLength);
            }
            else
            {
                header[3] = (byte)((unitLength - (plainLength % unitLength)) % unitLength);
            }

            SRSEncryption srs = new SRSEncryption();
            return srs.EncryptBlock(keyBytes, header);
        }
       
        #endregion

        #region Decrypt

        private void Decrypt()
        {
            // Get key and Cipher
            byte[] keyBytes = GetKey();
            int keyLength = keyBytes.Length;
            byte[] cipherBytes = Helper.StringToArrayByte(editorCipherText.TextBox.Text);
            int cipherLength = cipherBytes.Length;

            // Validate key length
            if (keyLength > cipherLength - 1)
            {
                ShowError("Cann't Decrypt. Key is too big.");
                return;
            }

            // Get Header
            byte[] header = new byte[keyLength];
            Array.Copy(cipherBytes, 0, header, 0, keyLength);

            // Get Body
            byte[] body = new byte[cipherLength - keyLength];
            Array.Copy(cipherBytes, keyLength, body, 0, cipherLength - keyLength);

            // Decrypt Header
            header = DecryptHeader(header, keyBytes);
            int mode = header[0];
            int unitLength = header[2];
            int padding = header[3];

            // Validation mode
            if (mode < 0 || mode > 3)
            {
                mode = 0;
            }

            // Validation unitLength
            if (unitLength > keyLength)
            {
                unitLength = keyLength;
            }

            // Decrypt Body
            SRSEncryption srs = GetEncryptionAlgorithm(mode);
            body = srs.Decrypt(keyBytes, body, unitLength);

            int newBodyLength = body.Length - padding;

            // Validation newBodyLength
            if (newBodyLength < 1)
            {
                newBodyLength = body.Length;
            }

            // Set to editor
            byte[] newBody = new byte[newBodyLength];
            Array.Copy(body, 0, newBody, 0, newBodyLength);
            editorPlainText.TextBox.Text = Helper.ArrayByteToString(newBody);
        }

        private byte[] DecryptHeader(byte[] header, byte[] keyBytes)
        {
            SRSEncryption srs = new SRSEncryption();

            return srs.DecryptBlock(keyBytes, header);
        }
        
        #endregion

        private byte[] GetKey()
        {
            byte[] keyBytes = Helper.StringToArrayByte(textBoxKey.Text);
            int keyLength = keyBytes.Length;

            if (keyLength < 8)
            {
                // Do Padding
                byte[] newKeyBytes = new byte[8];
                Array.Copy(keyBytes, 0, newKeyBytes, 0, keyLength);

                for (int i = keyLength; i < 8; ++i)
                {
                    newKeyBytes[i] = 100;
                }

                return newKeyBytes;
            }

            return keyBytes;
        }

        private SRSEncryption GetEncryptionAlgorithm(int mode)
        {
            SRSEncryption srs = new ECB();

            if (mode == 0)
            {
                srs = new ECB();
            }
            else if (mode == 1)
            {
                srs = new CBC();
            }
            else if (mode == 2)
            {
                srs = new CFB();
            }
            else if (mode == 3)
            {
                srs = new OFB();
            }
            return srs;
        }
       
        #endregion

        #region Validate Form
        private bool ValidateCommonForm()
        {
            // Check Key
            if (textBoxKey.Text == "")
            {
                ShowError("Key must be filled.");
                return false;
            }

            // Check Length of key
            if (textBoxKey.Text.Length > 256)
            {
                ShowError("Max of key's length is 256 character");
                return false;
            }

            return true;
        }

        private bool ValidateDecryptForm()
        {
            // Check Cipher Text
            if (editorCipherText.TextBox.Text.Length == 0)
            {
                ShowError("Cipher text must be filled");
                return false;
            }

            return true;
        }

        private bool ValidateEncryptForm()
        {
            // Check Plain Text
            if (editorPlainText.TextBox.Text.Length == 0)
            {
                ShowError("Plain text must be filled");
                return false;
            }
            
            return true;
        }
        #endregion

        #region Helper
        private void ShowError(string p)
        {
            MessageBox.Show(p, "Form Validation");
        }
        #endregion
    }
}
